﻿#include "cc2dv3.h"
#include "csb.h"
#include "csbmath.h"

/*********************| static data |*********************/
static cc2dv3*			__cc2dv3 = NULL;
static float			__def_fps = 0.0154f;


/*********************| extern C func |*********************/
CSB_DLL void Size2CP(const Size& s, convex_polygon_t* out)
{
	CSB_NO_VRET(out);
	out->pnum = 4;
	const float w2 = s.width / 2.0f;
	const float h2 = s.height / 2.0f;
	out->points[0].x = out->points[3].x = -w2;
	out->points[0].y = out->points[1].y = h2;
	out->points[1].x = out->points[2].x = w2;
	out->points[2].y = out->points[3].y = -h2;
}

CSB_DLL void CCRect2CP(const Rect& rect, convex_polygon_t* out)
{
	CSB_NO_VRET(out);
	out->pnum = 4;
	CP_STACK_4(tmp);
	Size2CP(rect.size, &tmp);
	elebase_t e;
	Vec2 mid(rect.getMidX(), rect.getMidY());
	COORD_POS_CONVERT(mid, e.pos);
	e.rotate = 0;
	e.scale.xs = e.scale.ys = 1.0f;
	CP_elebase_coll(&e, &tmp, out);
}

CSB_DLL void Size2SC(const Size& s, simple_collision_t* out)
{
	CSB_NO_VRET(out);
	float ps[8];
	const float w2 = s.width / 2.0f;
	const float h2 = s.height / 2.0f;
	ps[0] = ps[6] = -w2;
	ps[1] = ps[3] = h2;
	ps[2] = ps[4] = w2;
	ps[5] = ps[7] = -h2;
	SC_add_ele(out, ps, SC_ELE_POLYGON, 4);
}


CSB_DLL void CCRect2SC(const Rect& s, simple_collision_t* out)
{
	CSB_NO_VRET(out);
	SC_STACK(tmp);
	Size2SC(s.size, &tmp);
	elebase_t e;
	Vec2 mid(s.getMidX(), s.getMidY());
	COORD_POS_CONVERT(mid, e.pos);
	e.rotate = 0;
	e.scale.xs = e.scale.ys = 1.0f;
	SC_elebase_coll(&e, &tmp, out);
}

/*********************| function in SimpleBindProto |*********************/
void SimpleBindProto::updateEleBase(BindProto::bindele_t* p)
{
	CSB_NO_VRET(_bindObj);
	Node* bindNode = (Node*)_bindObj;
	csobj_t* po = p->pcs->pobj;
	// 注意坐标转换
	if (CSB_FLAG_TEST(p->flag, BindProto::UPDATE_PASSIVE) ||
	    !CSB_FLAG_TEST(p->flag, BindProto::FIRST_SETUPED)) {
		// 被动的获取信息
		Vec2 tp = bindNode->getPosition();
		tp.x += p->posOffset.x;
		tp.y += p->posOffset.y;
		COORD_POS_CONVERT(tp, po->ele.pos);
		po->ele.scale.xs = bindNode->getScaleX();
		po->ele.scale.ys = bindNode->getScaleY();
		csobj_set_rotate(po,bindNode->getRotation() + p->angleOffset,p->pcs->pobjdata->type);
		p->flag |= BindProto::FIRST_SETUPED;
	} else {
		// 设置主动位置
		Vec2 tp;
		COORD_POS_CONVERT(po->ele.pos, tp);
		tp.x -= p->posOffset.x;
		tp.y -= p->posOffset.y;
		bindNode->setPosition(tp);
		bindNode->setScaleX(po->ele.scale.xs);
		bindNode->setScaleY(po->ele.scale.ys);
		bindNode->setRotation(po->ele.rotate - p->angleOffset);
	}
}

void SimpleBindProto::bindObjRelease()
{
	if (_bindObj) {
		Node* p = (Node*)_bindObj;
		p->release();
		_bindObj = NULL;
	}
}

SimpleBindProto::SimpleBindProto(BindHelperProto* helper, Node* bindNode) :
	BindProto(helper, (void*)bindNode)
{
	if (bindNode) {
		bindNode->retain();
	}
}


SimpleBindProto::~SimpleBindProto()
{
	bindObjRelease();
}

void SimpleBindProto::updateBulletWithEle(const elebase_t& ele, void* pb)
{
	Node* pn = (Node*)pb;
	Vec2 tp;
	COORD_POS_CONVERT(ele.pos, tp);
	pn->setPosition(tp);
	pn->setRotation(ele.rotate);
	pn->setScaleX(ele.scale.xs);
	pn->setScaleY(ele.scale.ys);
}

/*********************| function in cc2dv3 |*********************/
cc2dv3::cc2dv3 () : _timeScale(0)
{
	this->onEnter();
	this->onEnterTransitionDidFinish();
	debugBuDrawNode = NULL;
}

cc2dv3::~cc2dv3 ()
{
	this->unscheduleUpdate();
	unbindAll(true);
	unloadAll();
	showBuDrawNode(false);
}

bool cc2dv3::init(const Size& winSize, Scheduler* ps)
{
	bool r = CSBBindMan::init(winSize.width, winSize.height);
	// 生成单例
	if (r) {
		cc2dv3::instance()->setScheduler(ps);
	}
	return r;
}

void cc2dv3::end()
{
	if (CSBBindMan::end()) {
		__cc2dv3->onExit();
		delete __cc2dv3;
		__cc2dv3 = NULL;
	}
}

cc2dv3*	cc2dv3::instance()
{
	CSB_YES_RET(__cc2dv3, __cc2dv3);
	__cc2dv3 = new cc2dv3();
	return __cc2dv3;
}

void cc2dv3::setTargetFPS(unsigned int n)
{
	__def_fps = 1.0f / (float)n;
	Director::getInstance()->setAnimationInterval(__def_fps);
	__def_fps -= 0.006f;
}

unsigned char*cc2dv3::loadCSBFileData(const char* path)
{
	ssize_t l = 0;
	return FileUtils::getInstance()->getFileData(path, "rb", &l);
}

bool cc2dv3::sc_for_draw(int type, const float* pp, uint16_t pn, void* udata)
{
	DrawNode* dnode = (DrawNode*)udata;
	if (SC_ELE_CIRCLE == type) {
		// 使用20多边形来模仿圆形
		dnode->drawCircle(Vec2(pp[0], COORD_Y_CONVERT(pp[1])), pp[2], 0, 10, false, Color4F(0, 1.0f, 0, 0.8f));
	} else {
		Vec2 ps[SC_PNUM_LIMIT / 2];
		for (uint16_t i = 0, j = 0; j < pn; ++i, j += 2) {
			ps[i].x = pp[j];
			ps[i].y = COORD_Y_CONVERT(pp[j + 1]);
		}
		dnode->drawPoly(ps, pn / 2, true, Color4F(0, 1.0f, 0, 1.0f));
	}
	return true;
}

void cc2dv3::showBuDrawNode(bool show)
{
	Scene* ps = Director::getInstance()->getRunningScene();
	CSB_NO_VRET(ps);
	if (show) {
		if (debugBuDrawNode && debugBuDrawNode->getParent())
			return;
		debugBuDrawNode = DrawNode::create();
		ps->addChild(debugBuDrawNode);
	} else {
		if (!debugBuDrawNode)
			return;
		debugBuDrawNode->removeFromParent();
		debugBuDrawNode = NULL;
	}
}

void cc2dv3::drawDebugInfo(convex_polygon_t& cp)
{
	if (debugBuDrawNode) {
		Vec2 ps[CP_POINT_LIMIT];
		for (size_t i = 0; i < cp.pnum; ++i) {
			ps[i].x = cp.points[i].x;
			ps[i].y = COORD_Y_CONVERT(cp.points[i].y);
		}
		debugBuDrawNode->drawPoly(ps, cp.pnum, true, Color4F(0, 1.0f, 0, 1.0f));
	}
}

void cc2dv3::drawDebugInfo(simple_collision_t& sc)
{
	if (debugBuDrawNode) {
		SC_foreach(&sc, cc2dv3::sc_for_draw, (void*)debugBuDrawNode);
	}
}

void cc2dv3::setScheduler(Scheduler* scheduler)
{
	if (scheduler) {
		Node::setScheduler(scheduler);
	} else {
		Node::setScheduler(Director::getInstance()->getScheduler());
	}
	this->scheduleUpdate();
}

void cc2dv3::update(float dt)
{
	_timeScale += dt;
	if (_timeScale >= __def_fps) {
		_timeScale = 0;
		if (debugBuDrawNode)
			debugBuDrawNode->clear();
		CSBBindMan::updateOnce();
	}
}
